package math_utils

import "confs/gen/common"

type Vector2D struct {
	X ZNumber
	Y ZNumber
}

func MakeVecto2dByInt64(x, y int64) Vector2D {
	return Vector2D{
		X: MakeZNumberByInt64(x),
		Y: MakeZNumberByInt64(y),
	}
}

func MakeVecto2dByFloat64(x, y float64) Vector2D {
	return Vector2D{
		X: MakeZNumberByFloat64(x),
		Y: MakeZNumberByFloat64(y),
	}
}

func MakeVector2dByVector(other Vector2D) Vector2D {
	return Vector2D{
		X: other.X,
		Y: other.Y,
	}
}

func MakeVector2dByZNumber(x ZNumber, y ZNumber) Vector2D {
	return Vector2D{
		X: x,
		Y: y,
	}
}

func MakeVector2dByProto(other *common.Vector2D) Vector2D {
	return Vector2D{
		X: MakeByReal(other.X),
		Y: MakeByReal(other.Y),
	}
}

func (v Vector2D) Mul(other ZNumber) Vector2D {
	res := Vector2D{}
	res.X = v.X.Mul(other)
	res.Y = v.Y.Mul(other)
	return res
}

func (v Vector2D) Dlv(other ZNumber) Vector2D {
	if other.IsZero() {
		return Vector2D{}
	} else {
		res := Vector2D{}
		res.X = v.X.Dlv(other)
		res.Y = v.Y.Dlv(other)
		return res
	}
}

func (v Vector2D) Add(other Vector2D) Vector2D {
	res := Vector2D{}
	res.X = v.X.Add(other.X)
	res.Y = v.Y.Add(other.Y)
	return res
}

func (v Vector2D) AddByZNumber(other ZNumber) Vector2D {
	res := Vector2D{}
	res.X = v.X.Add(other)
	res.Y = v.Y.Add(other)
	return res
}

func (v Vector2D) Sub(other Vector2D) Vector2D {
	res := Vector2D{}
	res.X = v.X.Sub(other.X)
	res.Y = v.Y.Sub(other.Y)
	return res
}

func (v Vector2D) Dot(other Vector2D) ZNumber {
	return v.X.Mul(other.X).Add(v.Y.Mul(other.Y))
}

func (v Vector2D) Cross(other Vector2D) ZNumber {
	return v.X.Mul(other.Y).Sub(other.X.Mul(v.Y))
}

func (v Vector2D) Normal() Vector2D {
	if v.X.IsZero() && v.Y.IsZero() {
		return Vector2D{}
	} else {
		temp := FloatSqrt(v.X.Mul(v.X).Add(v.Y.Mul(v.Y)))
		res := Vector2D{}
		res.X = v.X.Dlv(temp)
		res.Y = v.Y.Dlv(temp)
		return res
	}
}

func (v Vector2D) LengthSquare() ZNumber {
	return v.X.Mul(v.X).Add(v.Y.Mul(v.Y))
}

func (v Vector2D) Length() ZNumber {
	return FloatSqrt(v.X.Mul(v.X).Add(v.Y.Mul(v.Y)))
}

func (v Vector2D) IsZero() bool {
	return v.X.IsZero() && v.Y.IsZero()
}

func (v Vector2D) MulByMatrix(other Matrix2) Vector2D {
	res := Vector2D{}
	res.X = v.X.Mul(other.M11).Add(v.Y.Mul(other.M21))
	res.Y = v.X.Mul(other.M12).Add(v.Y.Mul(other.M22))
	return res
}

func (v Vector2D) Neg() Vector2D {
	res := Vector2D{}
	res.X = v.X.Neg()
	res.Y = v.Y.Neg()
	return res
}

func (v Vector2D) ToVector2D() *common.Vector2D {
	res := &common.Vector2D{}
	res.X = v.X.Value
	res.Y = v.Y.Value
	return res
}

func (v Vector2D) SetRealValue(x, y int64) {
	v.X.Value = x
	v.Y.Value = y
}
